package com.wex.cookbook.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.HashSet;
import java.util.Set;

/**
 *Jwt相关配置
 * @author : wex
 * @createTime : 2023/10/17 10:56
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class JwtTokenSecurityConfig extends WebSecurityConfigurerAdapter {
    //记录登录在线得账号列表清单
    public static final Set<String> accountOnlineList = new HashSet<>();

    //允许匿名访问的
    public static final String[] ALLOW_ASK = {
            //登录
            "/userinfo/login",
            //注册
            "/userinfo/register",
            //验证码
            "/verifyCode"
    };
    //允许访问的静态资源
    public static final String[] STATIC_ALLOW_ASK = {
            "/swagger**/**",
            "/doc.html",
            "/webjars/**",
            "/swagger-ui.html",
            "/swagger-resources/**",
            "/v2/api-docs**",
            "/verifyCode"
    };
    @Autowired
    private UserDetailServiceImpl userDetailService;
    @Autowired
    private AuthenticationTokenFilter authenticationTokenFilter;

    @Autowired
    private AuthenticationEntryPointImpl authenticationEntryPoint;
    @Autowired
    private AccessDeniedHandlerImpl accessDeniedHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService);
    }

    @Bean
    BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // 禁用 csrf, 由于使用的是JWT，我们这里不需要csrf
        http.cors().and().csrf().disable()
                // 基于token，所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

                .and()
                .authorizeRequests()
                // 跨域预检请求
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

                // 允许匿名访问：未登录可以访问，已登录不能访问
                .antMatchers(ALLOW_ASK).permitAll()
                // .antMatchers("/login").permitAll()// 登录或未登录都能访问
                // swagger
                .antMatchers(STATIC_ALLOW_ASK).permitAll()
                // 其他所有请求需要身份认证
                .anyRequest().authenticated()
                .and()
                .httpBasic()
/*
                 .and()
                .successHandler(AuthenticationSuccessHandler) // 登录成功 (登录生成生成token，response )
                .failureHandler(AuthenticationFailureHandler) // 登录失败
                .permitAll()*/
        ;
        // 退出登录处理器
        //http.logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler());

        // 开启登录认证流程过滤器
        http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);


        // 配置异常处理器
        http.exceptionHandling()
                // 认证失败
                .authenticationEntryPoint(authenticationEntryPoint)
                // 授权失败
                .accessDeniedHandler(accessDeniedHandler);

    }
}
